#include "tools.h"
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "color.h"
#include <stdarg.h>

// log functions
void
debug(const char* fmt, ...){
    fputs("[DEBU] ", stderr);

    va_list list;
    va_start(list, fmt);
    vfprintf(stderr, fmt, list);
    fputs("\n", stderr);
}

void 
info(const char* fmt, ...){
    // blue info
    set_term_color(SetForeBLU, SetBRIGHT, 0);

    fputs("[INFO] ", stderr);

    reset_term_color();

    va_list list;
    va_start(list, fmt);
    vfprintf(stderr, fmt,list);
    fputs("\n", stderr);
}

void 
warn(const char* fmt, ...){
    // gree info
    set_term_color(SetForeBLU, SetBRIGHT, 0);

    fputs("[WARN] ", stderr);

    reset_term_color();
    
    va_list list;
    va_start(list, fmt);

    vfprintf(stderr, fmt,list);
    fputs("\n", stderr);
}

void 
error(const char* fmt, ...){
    // red info
    set_term_color(FORERED, SetBRIGHT, 0);
    fputs("[Err ] ", stderr);
    reset_term_color();

    va_list list;
    va_start(list, fmt);

    vfprintf(stderr, fmt,list);
    fputs("\n", stderr);
}
// print an error message and exit
void 
error_exit(const char* errorcmd, const char* errormsg){
    if (errormsg){
        error(errormsg);
    }
    if (errorcmd){
        
    }
        
        perror(errorcmd);
    exit(-1);
}

// 终端颜色
void set_term_color(const char* c, const char* c2, const char* c3){
    if (c)
        fputs(c,stderr);
    if (c2)
        fputs(c2, stderr);
    if (c3)
        fputs(c3, stderr);
}

void reset_term_color(){
    fputs(RESETTEXT, stderr);
}
// end 终端颜色

int getTcpServerSocket(unsigned short portNumber){
    int sockfd;

    struct sockaddr_in servaddr;
    servaddr.sin_port = htons(portNumber);
    servaddr.sin_addr.s_addr = INADDR_ANY;
    servaddr.sin_family = AF_INET;

    // get sock
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
        return sockfd;

    // bind socket
    if (bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
    {
        return -1;
    }

    // listen to socket
    if (listen(sockfd, 5) < 0)
        return -1;

    return sockfd;
}

int getTcpClientSocket(const char* server, int serverPort){
    struct sockaddr_in servAddr;
    bzero(&servAddr, sizeof(servAddr));

    int clisock;

    clisock = socket(AF_INET, SOCK_STREAM, 0);
    if (clisock < 0){
        return -1;
    }

    //resolve server
    struct hostent* host = NULL;
    host = gethostbyname(server);

    if (host == NULL || host->h_addr == NULL)
        goto oops;
    printf("address: %s\n", inet_ntoa(*(struct in_addr*)(host->h_addr)));

    // set server socket
    servAddr.sin_family = AF_INET;
    // set server address

    bcopy((char*)host->h_addr,
            (char*)&servAddr.sin_addr.s_addr,
            host->h_length);

    // set server port
    servAddr.sin_port = htons(serverPort);

    // connect to server
    if (connect(clisock, (struct sockaddr*)&servAddr, sizeof(servAddr)) < 0)
        goto oops;

    return clisock;
oops:
    free(host);
    return -1;
}


// 上面的封装还是有代码冗余
// 重新封装一下
//
// 服务器端（passive socket）
// 需要知道的信息有：
// 监听端口号，
// 使用tcp还是udp
int
get_server_socket(int portNumber, int type, int qlen){
    int sockfd;
    socklen_t addrlen;

    struct sockaddr_in addr;
    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(portNumber);
    addr.sin_addr.s_addr = INADDR_ANY;

    addrlen = sizeof(addr);

    // get socket
    if ((sockfd = socket(AF_INET, type, 0)) < 0)
            return sockfd;

    // bind
    if (bind(sockfd, (struct sockaddr*)&addr, addrlen) < 0)
        return -1;

    // listen
    if (type == SOCK_STREAM && listen(sockfd, qlen) < 0)
        return -1;

    return sockfd;
}

// 客户端
// 需要知道的信息有：
// 1. 服务器的地址（ip/domain）
// 2. 服务器的端口
// 3. 使用的协议(tcp/udp)
int
connectTo(struct in_addr sin_addr, int portNumber, int type){
    int sockfd;
    struct sockaddr_in addr;
    socklen_t addrlen = sizeof(addr);

    bzero(&addr, addrlen);

    // set address
    addr.sin_addr = sin_addr;
    
    // set port
    addr.sin_port = htons(portNumber);
    addr.sin_family = AF_INET;

    // create socket
    sockfd = socket(AF_INET, type, 0);
    if (sockfd < 0)
        return sockfd;

    // connect
    if (connect(sockfd, (struct sockaddr*)&addr, addrlen) < 0)
        return -1;
    return sockfd;
}

struct sockaddr_in
get_sockaddr_in(int portNumber, struct in_addr sin_addr){
    struct sockaddr_in addr;
    bzero(&addr, sizeof(addr));

    addr.sin_port = htons(portNumber);
    addr.sin_addr = sin_addr;
    // 万年不变的AF_INET
    addr.sin_family = AF_INET;

    return addr;
}

int
get_in_addr_by_name_or_ip(const char* name_or_ip, struct in_addr* sin_addr){
    struct hostent* hent = NULL;

    if (sin_addr == NULL)
        return -1;

    hent = gethostbyname(name_or_ip);
    if (hent == NULL || hent->h_addr == NULL) {
        return -1;
    }

    bcopy(hent->h_addr, sin_addr, hent->h_length);

    return 0;
}

void
safe_exit(int n) {
    printf("exit");
    exit(0);
}

void
register_safe_exit_on_sigint() {
    signal(SIGINT, safe_exit);
}

